package weiyi.security.config;

import com.weiyi.common.common.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import weiyi.security.config.Component.*;
import weiyi.security.config.Component.dynamicSecurity.DynamicAccessDecisionManager;
import weiyi.security.config.Component.dynamicSecurity.DynamicSecurityFilter;
import weiyi.security.config.Component.dynamicSecurity.DynamicSecurityMetadataSource;

import java.util.List;
import java.util.Map;


/**
 * @Author PZC
 *
 * springsecurity全局配置类
 */

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired(required = false)
    StaticResourceRoleSource staticResourceRoleSource;

    @Autowired(required = false)
    private DynamicSecurityMetadataSource dynamicSecurityService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();
        for(String  url: ignoredUrlsConfig().getUrls()){
            registry.antMatchers(url).permitAll();
        }


        if(staticResourceRoleSource!=null) {
            //一个resource对应多个user
            Map<String, List<String>> resourceRole = staticResourceRoleSource.getStaticResource();

            //循环注册registry.antMatchers("/product").hasAnyAuthority("xxx管理员")
            for (String resource : resourceRole.keySet()) {

                // 将List转换数组， 将object[] 转换string[]
                List<String> roles = resourceRole.get(resource);
                registry.antMatchers(resource).hasAnyAuthority(roles.toArray(new String[roles.size()]));
            }
        }
        //允许http的预请求，以支持跨域
        registry.antMatchers(HttpMethod.OPTIONS).permitAll();

        registry
                //任何请求都必须经过认证
                .anyRequest()
                //.authenticated()
                .permitAll()//测试的时候允许所有请求,关闭过滤器
        .and()
                //开启跨域
                .cors()
        .and()
                //关闭csrf，因为使用了jwt，已经不会出现csrf的安全问题
                .csrf()
                .disable()
                //Spring Security will never create an HttpSession and it will never use it to obtain the SecurityContext
                //在任何情况下都不会创建session
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
                //异常处理，默认情况遇到异常SpringSecurity会抛回HTML页面，而我们希望它抛回的是消息
                .exceptionHandling()
                .accessDeniedHandler(accessDeniedHandlerResult())
                .authenticationEntryPoint(authenticationEntryPoint())
        .and()
                //将Jwt认证过滤器加到
                .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        if(dynamicSecurityService!=null){
            registry.and().addFilterBefore(dynamicSecurityFilter(), FilterSecurityInterceptor.class);
        }
    }


    @Bean
    public IgnoredUrlsConfig ignoredUrlsConfig(){
        return new IgnoredUrlsConfig();
    }

    @Bean
    public JwtTokenUtil jwtTokenUtil(){
        return new JwtTokenUtil();
    }

    @Bean
    public AccessDeniedHandlerResult accessDeniedHandlerResult(){
        return new AccessDeniedHandlerResult();
    }

    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return new AuthenticationEntryPointResult();
    }

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter(){
        return new JwtAuthenticationFilter();
    }

    /**
     * 作用：根据当前请求url获取对应角色
     * @return
     */
    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicAccessDecisionManager dynamicAccessDecisionManager() {
        return new DynamicAccessDecisionManager();
    }

    /**
     * 作用：在FilterSecurityInterceptor前面的自定义过滤器
     * @return
     */
    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicSecurityFilter dynamicSecurityFilter() {
        return new DynamicSecurityFilter();
    }

    /**
     * 作用：鉴权
     * @return
     */
    @ConditionalOnBean(name = "dynamicSecurityService")
    @Bean
    public DynamicSecurityMetadataSource dynamicSecurityMetadataSource() {
        return new DynamicSecurityMetadataSource();
    }
}
